package martin.tpfinal.grabar.grafico;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.Line2D;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;

import javax.sound.sampled.AudioFormat;
import javax.swing.JPanel;

/**
 * Render a WaveForm.
 */
class SamplingGraph extends JPanel implements Runnable {


	private static final long serialVersionUID = 1L;
	private Thread thread;
    private Font font12 = new Font("serif", Font.PLAIN, 12);
    private Color jfcBlue = new Color(204, 204, 255);
    private Color pink = new Color(255, 175, 175);
	private VentanaPrincipal ventana;


    public SamplingGraph(VentanaPrincipal ventana) {
        setBackground(new Color(20, 20, 20));
        this.ventana=ventana;
    }


    public void createWaveForm(byte[] audioBytes) {

        ventana.getLines().removeAllElements();  // clear the old vector

        AudioFormat format = ventana.getAudioInputStream().getFormat();
        if (audioBytes == null) {
            try {
                audioBytes = new byte[ (int) (ventana.getAudioInputStream().getFrameLength() * format.getFrameSize())];
                ventana.getAudioInputStream().read(audioBytes);
            } catch (Exception ex) { 
                ventana.reportStatus(ex.toString());
                return; 
            }
        }

        Dimension d = getSize();
        int w = d.width;
        int h = d.height-15;
        int[] audioData = null;
        if (format.getSampleSizeInBits() == 16) {
             int nlengthInSamples = audioBytes.length / 2;
             audioData = new int[nlengthInSamples];
             if (format.isBigEndian()) {
                for (int i = 0; i < nlengthInSamples; i++) {
                     /* First byte is MSB (high order) */
                     int MSB = (int) audioBytes[2*i];
                     /* Second byte is LSB (low order) */
                     int LSB = (int) audioBytes[2*i+1];
                     audioData[i] = MSB << 8 | (255 & LSB);
                 }
             } else {
                 for (int i = 0; i < nlengthInSamples; i++) {
                     /* First byte is LSB (low order) */
                     int LSB = (int) audioBytes[2*i];
                     /* Second byte is MSB (high order) */
                     int MSB = (int) audioBytes[2*i+1];
                     audioData[i] = MSB << 8 | (255 & LSB);
                 }
             }
         } else if (format.getSampleSizeInBits() == 8) {
             int nlengthInSamples = audioBytes.length;
             audioData = new int[nlengthInSamples];
             if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
                 for (int i = 0; i < audioBytes.length; i++) {
                     audioData[i] = audioBytes[i];
                 }
             } else {
                 for (int i = 0; i < audioBytes.length; i++) {
                     audioData[i] = audioBytes[i] - 128;
                 }
             }
        }
        
        int amplitud=20;
        
        int frames_per_pixel = audioBytes.length / format.getFrameSize()/w;
        byte my_byte = 0;
        double y_last = 0;
        int numChannels = format.getChannels();
        for (double x = 0; x < w && audioData != null; x++) {
            int idx = (int) (frames_per_pixel * numChannels * x);
            if (format.getSampleSizeInBits() == 8) {
                 my_byte = (byte) audioData[idx];
            } else {
                 my_byte = (byte) (128 * audioData[idx] / 32768 );
            }
            double y_new = (double) (h * (128 - my_byte) / 256);
            ventana.getLines().add(new Line2D.Double(x, y_last+amplitud, x, y_new+amplitud));//agrego 'amplitud' de amplitud supuestamente
            y_last = y_new;
        }

        repaint();
    }


    public void paint(Graphics g) {

        Dimension d = getSize();
        int w = d.width;
        int h = d.height;
        int INFOPAD = 15;

        Graphics2D g2 = (Graphics2D) g;
        g2.setBackground(getBackground());
        g2.clearRect(0, 0, w, h);
        g2.setColor(Color.white);
        g2.fillRect(0, h-INFOPAD, w, INFOPAD);

        if (ventana.getErrStr() != null) {
            g2.setColor(jfcBlue);
            g2.setFont(new Font("serif", Font.BOLD, 18));
            g2.drawString("ERROR", 5, 20);
            AttributedString as = new AttributedString(ventana.getErrStr());
            as.addAttribute(TextAttribute.FONT, font12, 0, ventana.getErrStr().length());
            AttributedCharacterIterator aci = as.getIterator();
            FontRenderContext frc = g2.getFontRenderContext();
            LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
            float x = 5, y = 25;
            lbm.setPosition(0);
            while (lbm.getPosition() < ventana.getErrStr().length()) {
                TextLayout tl = lbm.nextLayout(w-x-5);
                if (!tl.isLeftToRight()) {
                    x = w - tl.getAdvance();
                }
                tl.draw(g2, x, y += tl.getAscent());
                y += tl.getDescent() + tl.getLeading();
            }
        } else if (ventana.getCapture().getThread() != null) {
            g2.setColor(Color.black);
            g2.setFont(font12);
            g2.drawString("Length: " + String.valueOf(ventana.getSeconds()), 3, h-4);
        } else {
            g2.setColor(Color.black);
            g2.setFont(font12);
            g2.drawString("Length: " + String.valueOf(ventana.getDuration()) + "  Position: " + String.valueOf(ventana.getSeconds()), 3, h-4);

            if (ventana.getAudioInputStream() != null) {
                // .. render sampling graph ..
                g2.setColor(jfcBlue);
                for (int i = 1; i < ventana.getLines().size(); i++) {
                    g2.draw((Line2D) ventana.getLines().get(i));
                }

                // .. draw current position ..
                if (ventana.getSeconds() != 0) {
                    double loc = ventana.getSeconds()/ventana.getDuration()*w;
                    g2.setColor(pink);
                    g2.setStroke(new BasicStroke(3));
                    g2.draw(new Line2D.Double(loc, 0, loc, h-INFOPAD-2));
                }
            }
        }
    }

    public void start() {
        thread = new Thread(this);
        thread.setName("SamplingGraph");
        thread.start();
        ventana.setSeconds(0);
    }

    public void stop() {
        if (thread != null) {
            thread.interrupt();
        }
        thread = null;
    }

    @SuppressWarnings("static-access")
	public void run() {
    	ventana.setSeconds(0);
        while (thread != null) {
            if ((ventana.getPlayback().getLine() != null) && (ventana.getPlayback().getLine().isOpen()) ) {

                long milliseconds = (long)(ventana.getPlayback().getLine().getMicrosecondPosition() / 1000);
                ventana.setSeconds( milliseconds / 1000.0 );
            } else if ( (ventana.getCapture().getLine() != null) && (ventana.getCapture().getLine().isActive()) ) {

                long milliseconds = (long)(ventana.getCapture().getLine().getMicrosecondPosition() / 1000);
                ventana.setSeconds(milliseconds / 1000.0);
            }

            try { thread.sleep(100); } catch (Exception e) { break; }

            repaint();
                            
            while ((ventana.getCapture().getLine() != null && !ventana.getCapture().getLine().isActive()) ||
                   (ventana.getPlayback().getLine() != null && !ventana.getPlayback().getLine().isOpen())) 
            {
                try { thread.sleep(10); } catch (Exception e) { break; }
            }
        }
        ventana.setSeconds(0);
        repaint();
    }
    
    
} // End class SamplingGraph

